// 重写
function def(obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    enumerable: !!enumerable,
    configurable: true,
    writable: true,
    value: val
  })
}
// 是否已经 是响应式数据
function observe(value, asRootData) {
  if (!isObject(value)) {
    return
  }
  // instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
  // 如果指定的对象自身有指定的属性，则静态方法 Object.hasOwn() 返回 true。如果属性是继承的或者不存在，该方法返回 false。
  if (hasOwn(value, '__ob__') && value instanceof Observer) {
    ob = value.__ob__
  } else {
    ob = new Observer(value)
  }
  return ob
}

function remove(arr, item) {
  if (arr.length) {
    const index = arr.indexOf(item)
    if (index > -1) {
      return arr.splice(index, 1)
    }
  }
}
// 属性劫持
function defineReactive(data, key, val) {
  const childOb = observe(val) //修改
  // 存放依赖
  const dep = new Dep()
  // getter setter
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get() {
      // 收集依赖
      dep.depdend()
      //收集Array的依赖
      if (childOb) {
        childOb.dep.depdend()
      }

      return val
    },
    set(newVal) {
      if (newVal === val) {
        return
      }
      val = newVal
      // 通知依赖
      dep.notify()
    }
  })
}


// 不支持 __proto__属性
const hasProto = "__proto__" in {};
// 返回一个由指定对象的所有自身属性的属性名（包括不可枚举属性但不包括 Symbol 值作为名称的属性）组成的数组。
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
// 重定向原型对象
function protoArgument(target, src, keys) {
  target.__proto__ = src
}
// 没有，则遍历复制所有属性
function copyArgument(target, src, keys) {
  for (let i = 0, l = keys.length; i < l; i++) {
    const key = keys[i]
    def(target, key, src[key])
  }
}


// 拦截器

// 获取数组的原型对象
const arrayProto = Array.prototype
// 使用 Object.create() 实现类式继承
export const arrayMethods = Object.create(arrayProto)

[
  'push',
  'pop',
  'shift',
  'unshift',
  'sort',
  'reverse',
  'splice'
].forEach(function (menthod) {
  // 缓存原始方法
  const original = arrayProto[menthod];
  def(arrayProto, menthod, function mutator(...args) {
    const result = original.applay(this, args)
    // 访问 Observer实例
    const ob = this.__ob__
    let inserted
    switch (menthod) {
      case push:
      case unshift:
        inserted = args
        break;
      case splice:
        inserted = args.slice(2)
        break;
    }
    // 侦测新增元素变化
    if (inserted) ob.observerArray(inserted)
    // 向依赖发送通知
    ob.dep.notify()
    // 触发依赖
    return result
  })
})


// 定义Dep 类
export class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  removeSub(sub) {
    remove(this.subs, sub)
  }
  depdend() {
    if (window.target) {
      this.addSub(window.target)
    }
  }
  notify() {
    const sub = this.subs.slice()
    for (let i = 0; i < sub.length; i++) {
      sub[i].update()
    }
  }
}

class Observer {
  constructor(value) {
    this.value = value
    // // 数组将收集依赖存放在 Observer中： 在拦截器和 getter中都能接受到
    this.dep = new Dep()
    // 新增 不可枚举的 __ob__属性，其值就是当前的 Observer 实例
    def(val, '__ob__', this)
    // 如果是数组
    if (Array.isArray(value)) {
      // const argument = hasProto ? protoArgument : copyArgument
      // argument(obj, arrayMethods, arrayKeys)
      this.observerArray(value)
    } else {
      this.walk(value)
    }
  }
  // 对象
  walk(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i], obj[keys[i]])
    }

  }

  // 侦测数组中的每一项
  observerArray(items) {
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])
    }

  }
}